import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto';
import { IEncryptor } from '../types';

/**
 * 加密实现类
 */
export class Crypto implements IEncryptor {
    /** 加密密钥 */
    private key: Buffer | null = null;
    
    /** 加密算法 */
    private readonly algorithm = 'aes-256-gcm';
    
    /** 编码格式 */
    private readonly encoding = 'base64';

    /**
     * 构造函数
     * @param key 密钥（可选）
     */
    constructor(key?: string) {
        if (key) {
            this.setKey(key);
        }
    }

    /**
     * 加密数据
     * @param data 要加密的数据
     */
    encrypt(data: string): string {
        if (!this.key) {
            throw new Error('Encryption key not set');
        }

        // 生成初始化向量
        const iv = randomBytes(16);
        
        // 创建加密器
        const cipher = createCipheriv(this.algorithm, this.key, iv);
        
        // 加密数据
        let encrypted = cipher.update(data, 'utf8', this.encoding);
        encrypted += cipher.final(this.encoding);
        
        // 获取认证标签
        const authTag = cipher.getAuthTag();
        
        // 组合加密数据、IV和认证标签
        const combined = JSON.stringify({
            iv: iv.toString(this.encoding),
            data: encrypted,
            authTag: authTag.toString(this.encoding)
        });

        return Buffer.from(combined).toString(this.encoding);
    }

    /**
     * 解密数据
     * @param encryptedData 加密的数据
     */
    decrypt(encryptedData: string): string {
        if (!this.key) {
            throw new Error('Encryption key not set');
        }

        try {
            // 解析加密数据
            const combined = JSON.parse(Buffer.from(encryptedData, this.encoding).toString());
            const iv = Buffer.from(combined.iv, this.encoding);
            const encrypted = combined.data;
            const authTag = Buffer.from(combined.authTag, this.encoding);

            // 创建解密器
            const decipher = createDecipheriv(this.algorithm, this.key, iv);
            decipher.setAuthTag(authTag);

            // 解密数据
            let decrypted = decipher.update(encrypted, this.encoding, 'utf8');
            decrypted += decipher.final('utf8');

            return decrypted;
        } catch (error) {
            throw new Error('Failed to decrypt data: ' + (error as Error).message);
        }
    }

    /**
     * 生成新的加密密钥
     */
    generateKey(): string {
        const salt = randomBytes(16);
        const key = scryptSync('', salt, 32);
        return key.toString(this.encoding);
    }

    /**
     * 设置加密密钥
     * @param key 密钥
     */
    setKey(key: string): void {
        // 将base64密钥转换为Buffer
        this.key = Buffer.from(key, this.encoding);
        
        // 验证密钥长度
        if (this.key.length !== 32) {
            throw new Error('Invalid key length. Key must be 32 bytes');
        }
    }
}
